package cc.liyinghao.service.impl;


import cc.liyinghao.common.bo.SysUserDetails;
import cc.liyinghao.common.pojo.SysUser;
import cc.liyinghao.response.LoginSuccessfulVo;
import cc.liyinghao.config.DefaultIpPrefixConfig;
import cc.liyinghao.mapper.SysUserMapper;
import cc.liyinghao.param.UserRegisterParam;
import cc.liyinghao.security.util.JwtTokenUtil;
import cc.liyinghao.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    private final DefaultIpPrefixConfig defaultIpPrefixConfig;
    private final StringRedisTemplate redisTemplate;
    private final SysUserMapper sysUserMapper;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenUtil jwtTokenUtil;

    /**
     * 注册接口
     */
    @Override
    public SysUser register(UserRegisterParam userRegisterParam) {
        //1.优先验证手机号对应的验证码
        try {
            redisTemplate.opsForValue().get(userRegisterParam.getPhoneNumber());
        } catch (Exception e) {
            throw new RuntimeException("验证码错误");
        }
        //2.验证用户名和手机号是否已注册
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(SysUser::getUsername, userRegisterParam.getUsername())
                .or()
                .eq(SysUser::getPhoneNumber, userRegisterParam.getPhoneNumber());
        SysUser user1 = sysUserMapper.selectOne(queryWrapper);
        if (user1 != null) {
            throw new RuntimeException("用户名或手机号已注册");
        }
        //3.将注册信息写入数据库
        SysUser user = new SysUser();
        BeanUtils.copyProperties(userRegisterParam, user);
        user.setCreateTime(new Date());
        user.setStatus(1);
        if (user.getHeadImgUrl() == null) {
            user.setHeadImgUrl(defaultIpPrefixConfig.getDefaultAvatar());
        }
        //将密码加密
        String encodePassword = passwordEncoder.encode(user.getPassword());
        user.setPassword(encodePassword);
        sysUserMapper.insert(user);
        return user;
    }

    @Override
    public void getValidationPhoneNumberCode(String phoneNumber) {
        //1.查询手机号是否已注册
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getPhoneNumber, phoneNumber);
        SysUser user = sysUserMapper.selectOne(queryWrapper);
        if (user != null) {
            throw new RuntimeException("手机号已注册");
        }
        //查询redis验证码是否已经发送
        String isIn = redisTemplate.opsForValue().get(phoneNumber);
        if (Objects.nonNull(isIn)) {
            throw new RuntimeException("验证码已发送，请稍后再试");
        }
        //生成验证码，6位随机数
        int code = (int) ((Math.random() * 9 + 1) * 100000);
        log.info("手机号：{}，验证码：{}", phoneNumber, code);
        redisTemplate.opsForValue().set(phoneNumber, String.valueOf(code), 60, TimeUnit.SECONDS);
    }

    @Override
    @Transactional
    public String updateAvatar(MultipartFile file, int userId) throws IOException {
        //1.文件重命名 上传的为二进制文件，没有后缀名
        String newFileName = UUID.randomUUID().toString().replace("-", ""); //获取uuid
        String path = Paths.get("").toAbsolutePath() + "/static/static/avatar-"; //获取当前项目路径
        //2.将文件上传到指定目录
        file.transferTo(new File(path + newFileName));
        //3.保存到数据库
        SysUser sysUser = new SysUser();
        sysUser.setId(userId);
        sysUser.setHeadImgUrl("avatar-" + newFileName);
        sysUserMapper.updateById(sysUser);
        return defaultIpPrefixConfig.getDefaultStaticIp() + sysUser.getHeadImgUrl();
    }

    /**
     * 登录接口，返回token
     */
    @Override
    public LoginSuccessfulVo login(String username, String password) {
        String token = null;
        SysUserDetails userDetails = null;
        LoginSuccessfulVo loginSuccessfulVo = null;
        try {
            userDetails = loadUserByUsername(username);
            if (!passwordEncoder.matches(password, userDetails.getPassword())) {
                throw new RuntimeException("用户名或密码错误");
            }
            //生成AuthenticationToken，目的是将用户信息放入SecurityContextHolder中 账号 密码 权限
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            //将authentication(认证过的用户信息)放入SecurityContextHolder中
            SecurityContextHolder.getContext().setAuthentication(authentication);
            //生成token
            token = jwtTokenUtil.generateToken(userDetails);
            loginSuccessfulVo = LoginSuccessfulVo.builder()
                    .token(token)
                    .tokenHead("Bearer ")
                    .username(userDetails.getUsername())
                    .phoneNumber(userDetails.getPhoneNumber())
                    .headImgUrl(defaultIpPrefixConfig.getDefaultStaticIp() + userDetails.getHeadImgUrl())
                    .email(userDetails.getEmail())
                    .id(userDetails.getId())
                    .build();
        } catch (AuthenticationException e) {
            log.error("登录异常:{}", e.getMessage());
        }
        return loginSuccessfulVo;
    }

    /**
     * 根据用户名获取用户信息
     */
    @Override
    public SysUserDetails loadUserByUsername(String username) {
        SysUser user = getSysUserByUsername(username);
        if (user != null) {
            return new SysUserDetails(user);
        }
        throw new RuntimeException("用户不存在");
    }

    @Override
    public SysUser getSysUserByUsername(String username) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, username);
        return sysUserMapper.selectOne(queryWrapper);
    }

}
